#######################################################
# Example of PingPong coupled DEVS using DEVS player
# Author: moonho.hwang@gmail.com
#   Date: Oct.19.2011
#######################################################
from XSY.DEVS.FRTDEVS import *
from XSY.DEVS.CoupledDEVS import *
from XSY.DEVS.SimEngine import SimEngine
from XSY.Set.Interval import *
from XSY.DEVS.VeriEngine import VeriEngine

class Timer(FRTDEVS):
   '''timer class'''
   def __init__(m, n, iv, tl, tu, parent=None):
      '''constructor'''
      FRTDEVS.__init__(m, n, parent) 
      m.iv = iv
      m.tl, m.tu = tl, tu

      m.addInputPorts('?s', '?r')
      m.addOutputPorts('!s')

   def delta_0(m):
      '''set the initial state'''
      m.phase = m.iv 

   def rv_tau(m):
      '''random lifespan scheduling function'''
      if m.phase == 'B':
         return TInterval(m.tl,m.tu) # 
      else:
         return float('inf') # 

   def delta_x(m, x):
      '''external transition function'''
      if x.port == m.IP['?r'] and m.phase == 'B':
	 m.phase = 'I'
         return True
      elif x.port == m.IP['?s'] and m.phase == 'I':
	 m.phase = 'B'
         return True
      else:
         return False
               
   def delta_y(m):
      '''output and internal transition function'''
      if m.phase == 'B':
         y = PortValue(m.OP["!s"])
         return y
   
   def get_state(m):
      '''get the state'''
      return m.phase

   def set_state(m, s):
      '''set the state as s'''
      m.phase = s

class Stopper(Timer):
   '''Stoper class derived from Timer class'''
   #def __init__(m, n, iv, tl, tu, parent=None):
   #   Timer.__init__(m,n,iv,tl,tu,parent)

   def delta_x(m, x):
      '''random external transition function'''
      if x.port == m.IP['?s'] and m.phase == 'I':
	 m.phase = 'B'
         return True
      else:
         return False

   def delta_y(m):
      '''random external transition function'''
      if m.phase == 'B':
         y = PortValue(m.OP["!s"])
	 m.phase = 'I'
         return y

def makeModel():
   '''make the coupled model of timer and stopper'''
   md1 = Timer('m1', 'I', 10, 20)
   md2 = Stopper('m2', 'I', 25, 35)

   cm = CoupledDEVS("")
   cm.addComponents(md1, md2)
   cm.addInputPorts('?s')
   cm.addOutputPorts('!s')
   cm.addCouples((md1.OP["!s"], md2.IP["?r"]), (md2.OP["!s"], md1.IP["?r"]))
   cm.addCouples((cm.IP["?s"], md1.IP["?s"]), (cm.IP["?s"], md2.IP["?s"]))
   return cm


def make_input_event(md):
   ''' a callback function for injection'''
   ip = md.IP['?s']
   if ip:
      return PortValue(ip)
   else:
      return None # inject None into timer 

def runSimulation(md):
   '''run a simulation run'''
   engine = SimEngine(md,make_input_event)

   #---- setting StepByStep and DES simulation only ----
   #engine.StepByStep = True
   engine.sfactor = float('inf')
   #----------------------------------------------------
   engine.runInteractiveMenu()

def runVerification(md):
   '''run the verification'''
   X = [PortValue(md.IP["?s"])]

   VE = VeriEngine(md, X, None, None)
   VE.runtimeInteractiveMenu()

if __name__ == '__main__':
   md = makeModel()

   c = True
   while c:
      s = raw_input('[s]im, [v]eri, e[x]it>')
      if s == 's' or s == 'sim': 
         runSimulation(md)
      elif s == 'v' or s == 'veri':
         runVerification(md)
      elif s == 'x' or s == 'exit':
         c = False
      else:
         print('%s is an invalid input!'%s)
      
   print "good bye~!" 
